#!/usr/bin/env python3

# Copyright (c) 2020 ASPEED Technology Inc.

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import argparse
import jstyleson
import sys
import os

INFO_VER = "1.1.0"
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))+'/'
INFO_DIR = ROOT_DIR + '../socsec/otp_info/'
OTP_INFO = [
    {
        'config': INFO_DIR+'a0_config.json',
        'strap': INFO_DIR+'a0_strap.json',
        'conf_name': 'a0_conf_info',
        'strap_name': 'a0_strap_info'
    },
    {
        'config': INFO_DIR+'a1_config.json',
        'strap': INFO_DIR+'a1_strap.json',
        'conf_name': 'a1_conf_info',
        'strap_name': 'a1_strap_info'
    },
    {
        'config': INFO_DIR+'a2_config.json',
        'strap': INFO_DIR+'a2_strap.json',
        'conf_name': 'a2_conf_info',
        'strap_name': 'a2_strap_info'
    },
    {
        'config': INFO_DIR+'a3_config.json',
        'strap': INFO_DIR+'a2_strap.json',
        'conf_name': 'a3_conf_info',
        'strap_name': 'a3_strap_info'
    }
]


def conf2info(config):
    ret = []
    for i in config:
        if 'info' not in i:
            continue
        dw_offset = i['dw_offset']
        bit_offset = i['bit_offset']
        if i['type'] == 'boolean':
            length = 1
            ret.append('\t{{ {}, {}, {}, {}, \"{}\" }},\n'.format(
                dw_offset, bit_offset, length, 0, i['info'][0]))
            ret.append('\t{{ {}, {}, {}, {}, \"{}\" }},\n'.format(
                dw_offset, bit_offset, length, 1, i['info'][1]))
        elif i['type'] == 'string':
            length = i['bit_length']
            info = i['info']
            for v in i['value']:
                bit = v['bit']
                tmp = info.format(v['value'])
                ret.append('\t{{ {}, {}, {}, {}, \"{}\" }},\n'.format(
                    dw_offset, bit_offset, length, bit, tmp))
        elif i['type'] == 'hex':
            length = i['bit_length']
            info = i['info']
            tmp = info.format('0x%x')
            ret.append('\t{{ {}, {}, {}, OTP_REG_VALUE, \"{}\" }},\n'.format(
                dw_offset, bit_offset, length, tmp))
        elif i['type'] == 'bit_shift':
            length = i['bit_length']
            info = i['info']
            tmp = info.format('%s')
            ret.append('\t{{ {}, {}, {}, OTP_REG_VALID_BIT, \"{}\" }},\n'.format(
                dw_offset, bit_offset, length, tmp))

    if ret.__len__() == 0:
        return ''
    ret[-1] = ret[-1][:-2] + '\n'
    return ''.join(ret)


def strap2info(config):
    ret = []
    for i in config:
        if 'info' not in i and i['type'] != 'reserved':
            continue
        bit_offset = i['bit_offset']
        if i['type'] == 'boolean':
            length = 1
            ret.append('\t{{ {}, {}, {}, \"{}\" }},\n'.format(
                bit_offset, length, 0, i['info'][0]))
            ret.append('\t{{ {}, {}, {}, \"{}\" }},\n'.format(
                bit_offset, length, 1, i['info'][1]))
        elif i['type'] == 'string':
            length = i['bit_length']
            info = i['info']
            for v in i['value']:
                bit = v['bit']
                tmp = info.format(v['value'])
                ret.append('\t{{ {}, {}, {}, \"{}\" }},\n'.format(
                    bit_offset, length, bit, tmp))
        elif i['type'] == 'reserved':
            length = i['bit_length']
            ret.append('\t{{ {}, {}, OTP_REG_RESERVED, \"Reserved\" }},\n'.format(bit_offset, length))

    if ret.__len__() == 0:
        return ''
    ret[-1] = ret[-1][:-2] + '\n'
    return ''.join(ret)


conf_str = ""
strap_str = ""
header_str = "\
/*\n\
 * Generated by info2header.py\n\
 * Do not edit it.\n\
 */\n\n"

header_str = header_str + "#define OTP_INFO_VER\t\t\"{}\"\n".format(INFO_VER)

with open(ROOT_DIR + 'otp_header.h', 'r') as header_fd:
    header_str = header_str + header_fd.read()

for i in OTP_INFO:
    conf_path = i['config']
    with open(conf_path, 'r') as config_info_fd:
        config_info = jstyleson.load(config_info_fd)
    conf_str = conf_str + \
        "static const struct otpconf_info {}[] = {{\n".format(i['conf_name'])
    conf_str = conf_str + conf2info(config_info)
    conf_str = conf_str + '};\n\n'

for i in OTP_INFO:
    strap_path = i['strap']
    with open(strap_path, 'r') as strap_info_fd:
        strap_info = jstyleson.load(strap_info_fd)
    strap_str = strap_str + \
        "static const struct otpstrap_info {}[] = {{\n".format(i['strap_name'])
    strap_str = strap_str + strap2info(strap_info)
    strap_str = strap_str + '};\n\n'

print(header_str + strap_str + conf_str)
with open(ROOT_DIR + 'otp_info.h', 'w') as out_fd:
    out_fd.write(header_str + strap_str + conf_str)
